package org.jugile.restapi.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jugile.util.*;

import org.jugile.restapi.common.*;



public abstract class OperationBase extends Entity {
	static Logger log = Logger.getLogger(OperationBase.class);
	
	public DOH getDoh() { return new DOH("Operation",getId()); }

	public void reindex(Domain d) {}
	
	// --- fields ---

	private String method;
	public String getMethod() { return method; }
	public Operation setMethod(String v) { method = v; d()._modified(this); return (Operation)this; }
 	private String tmpl;
	public String getTmpl() { return tmpl; }
	public Operation setTmpl(String v) { tmpl = v; d()._modified(this); return (Operation)this; }
 	private String model;
	public String getModel() { return model; }
	public Operation setModel(String v) { model = v; d()._modified(this); return (Operation)this; }
 	private String mimetype;
	public String getMimetype() { return mimetype; }
	public Operation setMimetype(String v) { mimetype = v; d()._modified(this); return (Operation)this; }
 	private String border;
	public String getBorder() { return border; }
	public Operation setBorder(String v) { border = v; d()._modified(this); return (Operation)this; }
  

 
	// --- connections ---

 
 
 

	// --- 1 - n ----

 

	// --- n - 1 ----

	private Type type;
	public Type getType() { return type; }
	public Operation setType(Type v) {
		d()._modified(this);
		return mapType(v);
	}
	protected Operation mapType(Type v) { 
		if (type != null) type._removeOperation((Operation)this);
		if (v != null) v._addOperation((Operation)this);
		type = v;
		return (Operation)this;
	}

	private PathItem pathItem;
	public PathItem getPathItem() { return pathItem; }
	public Operation setPathItem(PathItem v) {
		d()._modified(this);
		return mapPathItem(v);
	}
	protected Operation mapPathItem(PathItem v) { 
		if (pathItem != null) pathItem._removeOperation((Operation)this);
		if (v != null) v._addOperation((Operation)this);
		pathItem = v;
		return (Operation)this;
	}

 

	// --- n - n ----
 
	// --- life cycle methods ---
	public void delete() { delete(true); }
	public void delete(boolean ondelete) {
		if (ondelete) this.onDelete();
 		Type o1 = getType();
		if (o1 != null) o1.removeOperation((Operation)this);  
		PathItem o2 = getPathItem();
		if (o2 != null) o2.removeOperation((Operation)this);  
   		d().deleteOperation(getId());
 		d()._deleted(this);
	}

	public void onDelete() {} // override 
	public void onLoad(IDomain d) {} // override
	public void onWrite() {} // override
	public void onDeleteEvent() {} // override
	public void onSave() {} // override - not implemented yet
	
	public String toString() {
		String res = "";
		res += nn(method) + ";";
 		res += nn(tmpl) + ";";
 		res += nn(model) + ";";
 		res += nn(mimetype) + ";";
 		res += nn(border) + ";";
  		return res;
	}
	
	
	public final static String[] _flds = {
		"method",
		"tmpl",
		"model",
		"mimetype",
		"border",
  		"Type",
		"PathItem",
 	};
	public static String[] flds() { return _flds; }
	
	public void parseMethod(String v) {
	    if ("-".equals(v)) v = null;
		setMethod(v); return;
 	}
	public void parseTmpl(String v) {
	    if ("-".equals(v)) v = null;
		setTmpl(v); return;
 	}
	public void parseModel(String v) {
	    if ("-".equals(v)) v = null;
		setModel(v); return;
 	}
	public void parseMimetype(String v) {
	    if ("-".equals(v)) v = null;
		setMimetype(v); return;
 	}
	public void parseBorder(String v) {
	    if ("-".equals(v)) v = null;
		setBorder(v); return;
 	}
 
 
	public void parseType(String id) {
		if ("-".equals(id)) setType(null);
		else setType( (Type)d().getOrCreate("Type", id));
	}
	public void parsePathItem(String id) {
		if ("-".equals(id)) setPathItem(null);
		else setPathItem( (PathItem)d().getOrCreate("PathItem", id));
	}
 
	// ----- db persistence -----

	protected static String _getSelectFlds() {
		Buffer buf = new Buffer();
		buf.add("id_f,ts,host,vers");
		for (String fld : _flds) {
			buf.add(","+fld+"_f");
		}
		return buf.toString();
	}
	protected String _getUpdateFlds() {
		Buffer buf = new Buffer();
		for (int i = 0; i < _flds.length; i++) {
			if (i > 0) buf.add(",");
			buf.add(_flds[i]+"_f=?");
		}
		return buf.toString();		
	}
	
	protected void _readFlds(Domain d, List row) {
		_modified = row.get(1)==null?null:new Time((java.util.Date)row.get(1));
		String host = (String)row.get(2);
		setVersion((Integer)row.get(3));
		method = (String)row.get(4);
		tmpl = (String)row.get(5);
		model = (String)row.get(6);
		mimetype = (String)row.get(7);
		border = (String)row.get(8);
  		mapType(row.get(9)==null?null:Type.getOrCreate(d,(Integer)row.get(9)));
		mapPathItem(row.get(10)==null?null:PathItem.getOrCreate(d,(Integer)row.get(10)));
 
		// call onLoad
		onLoad(d);
		setVirgin(false);
	}

	
	protected void _writeFlds(DBConnection c) throws Exception {
		onWrite();
		// is it insert or update?
		if (isVirgin()) {
			c.prepare("insert into "+ _tablename+" set id_f=?,host=?,vers=?," + _getUpdateFlds());
			c.param(Long.parseLong(getId()));
			c.param(Domain.getHostName());
			c.param(1L);

			setWriteParams(c);
			
			try {
				c.execute();
			} catch(Exception se) {
				log.error("Failed to insert writeFlds Operation: " + getId());
				throw se;
			}
			setVersion(1L);
		} else {
			c.prepare("update "+ _tablename+" set host=?,vers=?," + _getUpdateFlds() + " where id_f=? AND vers=?");
			c.param(Domain.getHostName());
			c.param(getVersion()+1L); // increment db version
			
			setWriteParams(c);
			
			c.param(Long.parseLong(getId()));
			c.param(getVersion());
			try {
				int res = c.execute();
				if (res != 1) {
					fail("object not found: Operation " + getId() + " " + getVersion());
				}
			} catch(Exception se) {
				log.error("Failed to update writeFlds Operation: " + getId());
				throw se;
			}
			// increment mem object versions when db commit is ok
		}
	}

	private void setWriteParams(DBConnection c) throws Exception {
		c.param(trim(getMethod(),300));
		c.param(trim(getTmpl(),300));
		c.param(trim(getModel(),300));
		c.param(trim(getMimetype(),300));
		c.param(trim(getBorder(),300));
  		c.param(getType());
		c.param(getPathItem());
 	}

	private final static String _tablename = "operation_t";
	protected String _getTableName() { return _tablename; }

	protected static int _readAllUpdates(Domain d, DBConnection c, Time ts, String host) throws Exception {
		if (host == null) {
			c.prepare("select "+Operation._getSelectFlds()+" from "+_tablename+" where ts >= ?");			
			c.param(ts);
		} else {
			c.prepare("select "+Operation._getSelectFlds()+" from "+_tablename+" where ts >= ? AND host != ?");			
			c.param(ts);
			c.param(host);
		}
		int count = 0;
		for (List row : c.select()) {
			long id = (Integer)row.get(0);
			Operation o = getOrCreate(d,id);
			o._readFlds(d,row);
			count++;
		}
		return count;
	}
	
	private Time _modified;
	public Time getModifiedTime() { return _modified; }
	
	protected static Operation getOrCreate(Domain d, long id) {
		Operation o = d.getOperation(id);
		if (o == null) o = d._createEmptyOperation(id);
		return o;
	}

}